Clone graph [Hash table and BFS]

Time: O(N); Space: O(N); medium

Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.

OJ’s undirected graph serialization: Nodes are labeled uniquely.

We use as a separator for each node, and , as a separator for node label and each neighbor of the node.

Constraints:

  • 1 <= Node.val <= 100

  • Node.val is unique for each node.

  • Number of Nodes will not exceed 100.

  • There is no repeated edges and no self-loops in the graph.

  • The Graph is connected and all nodes can be visited starting from the given node.

Example 1:

Consider the serialized graph {0, 1, 2#1, 2#2, 2}.

The graph has a total of three nodes, and therefore contains three parts as separated by #.

First node is labeled as 0. Connect node 0 to both nodes 1 and 2. Second node is labeled as 1. Connect node 1 to node 2. Third node is labeled as 2. Connect node 2 to node 2 (itself), thus forming a self-cycle. Visually, the graph looks like the following:

   1
  / \
 /   \
0 --- 2
     / \
     \_/

Example 2:

Input: adjList = [[2,4],[1,3],[2,4],[1,3]]

Output: [[2,4],[1,3],[2,4],[1,3]]

Explanation:

  • There are 4 nodes in the graph.

  • 1st node (val = 1)’s neighbors are 2nd node (val = 2) and 4th node (val = 4).

  • 2nd node (val = 2)’s neighbors are 1st node (val = 1) and 3rd node (val = 3).

  • 3rd node (val = 3)’s neighbors are 2nd node (val = 2) and 4th node (val = 4).

  • 4th node (val = 4)’s neighbors are 1st node (val = 1) and 3rd node (val = 3).

[1]:
class UndirectedGraphNode:
    def __init__(self, x):
        self.label = x
        self.neighbors = []
[2]:
from collections import deque

class Solution(object):
    def cloneGraph(self, node):
        """
        :type node: UndirectedGraphNode
        :rtype: UndirectedGraphNode
        """
        if node == None:
            return None

        que = deque()
        que.append(node)

        visited = set()
        visited.add(node)

        nodes = {}
        idx = 0
        while idx != len(que):
            curr = que[idx]
            idx += 1
            nodes[curr] = UndirectedGraphNode(curr.label)
            for node in curr.neighbors:
                if node not in visited:
                    visited.add(node)
                    que.append(node)

        start_node = None

        for node in que:
            curr = nodes[node]
            for neighbor in node.neighbors:
                curr.neighbors.append(nodes[neighbor])
            if start_node == None:
                start_node = curr

        return start_node
[3]:
if __name__ == "__main__":
    s = Solution()
    node1 = UndirectedGraphNode('1')
    node2 = UndirectedGraphNode('2')
    node3 = UndirectedGraphNode('3')
    node4 = UndirectedGraphNode('4')
    node1.neighbors = [node2, node4]
    node2.neighbors = [node1, node3]
    node3.neighbors = [node2, node4]
    node4.neighbors = [node1, node3]

    cloned_graph = s.cloneGraph(node1)

    print(cloned_graph.label, end = '')
    print(' -> ' + cloned_graph.neighbors[0].label)
    print('  -> ' + cloned_graph.neighbors[1].label)

    print(cloned_graph.neighbors[0].label, end = '')
    print(' -> ' + cloned_graph.neighbors[0].neighbors[0].label)
    print('  -> ' + cloned_graph.neighbors[0].neighbors[1].label)

    print(cloned_graph.neighbors[1].label, end = '')
    print(' -> ' + cloned_graph.neighbors[1].neighbors[0].label)
    print('  -> ' + cloned_graph.neighbors[1].neighbors[1].label)

    print(cloned_graph.neighbors[0].neighbors[1].label, end = '')
    print(' -> ' + cloned_graph.neighbors[0].neighbors[1].neighbors[0].label)
    print('  -> ' + cloned_graph.neighbors[0].neighbors[1].neighbors[1].label)
1 -> 2
  -> 4
2 -> 1
  -> 3
4 -> 1
  -> 3
3 -> 2
  -> 4